package cn.sdack.go.users.service;

import cn.sdack.go.common.annotation.AfterAuthentication;
import cn.sdack.go.common.annotation.BeforeAuthentication;
import cn.sdack.go.common.entities.users.AuthorityEntity;
import cn.sdack.go.common.entities.users.RoleAuthorityEntity;
import cn.sdack.go.common.entities.users.RoleEntity;
import cn.sdack.go.common.entities.users.UserRoleEntity;
import cn.sdack.go.common.querys.users.RoleQuery;
import cn.sdack.go.users.dao.AuthorityDao;
import cn.sdack.go.users.dao.RoleAuthorityDao;
import cn.sdack.go.users.dao.RoleDao;
import cn.sdack.go.users.dao.UserRoleDao;
import com.alibaba.fastjson2.JSONObject;
import jakarta.transaction.Transactional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.*;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Optional;
import java.util.stream.Collectors;

import static org.springframework.data.domain.ExampleMatcher.GenericPropertyMatchers.endsWith;

/**
 * @author sdack
 * @date 2024/1/8
 */
@Service
public class RoleServiceImpl implements RoleService {

    @Autowired
    private RoleDao roleDao;

    @Autowired
    private RoleAuthorityDao roleAuthorityDao;

    @Autowired
    private AuthorityDao authorityDao;

    @Autowired
    private UserRoleDao userRoleDao;

    private final List<String> defaultCode = List.of("group","super"); // 保留值

    @Override
    public Page<RoleEntity> queryAll(RoleQuery param, int page, int pageSize) throws Exception {
        ExampleMatcher matcher = ExampleMatcher.matchingAny()
                .withIgnoreNullValues()
                .withMatcher(RoleQuery.CODE, endsWith());


        RoleEntity query = JSONObject.parseObject(JSONObject.toJSONString(page), RoleEntity.class);
        Example<RoleEntity> example = Example.of(query, matcher);
        return roleDao.findAll(example, PageRequest.of(page <= 0 ? 0 : page - 1, pageSize, Sort.by(Sort.Order.desc("id"))));
    }

    @AfterAuthentication
    @Override
    public RoleEntity getById(Long id) throws Exception {
        Optional<RoleEntity> optional = roleDao.findById(id);
        if (optional.isEmpty()) {
            throw new IllegalAccessException("non-existent");
        }
        return optional.get();
    }

    @BeforeAuthentication
    @Transactional
    @Override
    public RoleEntity add(RoleEntity param) throws Exception {
        param.setId(null);
        for (String it : defaultCode) {
            if (param.getCode().toLowerCase(Locale.ENGLISH).contains(it)) {
                throw new IllegalAccessException("Code值 禁止使用");
            }
        }
        RoleEntity nameKey = roleDao.findByGidAndCodeAndDelIsNull(param.getGid(),param.getCode());
        if (nameKey != null) {
            throw new IllegalAccessException("角色 Code 已存在");
        }
        LocalDateTime now = LocalDateTime.now();
        List<RoleAuthorityEntity> list = roleAuthorityDao.findAllByGidAndRoleCodeAndDelIsNull(param.getGid(),param.getCode());
        list.stream().filter(it -> it.getDel() == null).forEach(item -> item.setDel(now));
        roleAuthorityDao.saveAll(list);
        return roleDao.save(param);
    }

    @Transactional
    @Override
    public RoleEntity set(RoleEntity param) throws Exception {
        RoleEntity entity = getById(param.getId());
        for (String it : defaultCode) {
            if (param.getCode().toLowerCase(Locale.ENGLISH).contains(it)) {
                throw new IllegalAccessException("Code值 禁止使用");
            }
        }

        RoleEntity oldEntity = roleDao.findByGidAndCode(entity.getGid(),param.getCode());
        if (oldEntity != null && entity.getId() != oldEntity.getId().longValue()) {
            throw new IllegalAccessException("角色Code重复");
        }
        if (!entity.getCode().equals(param.getCode())) { // 更换key值
            List<UserRoleEntity> list = userRoleDao.findAllByGidAndRoleCodeAndDelIsNull(entity.getGid(),entity.getCode());
            list.forEach(it -> it.setRoleCode(param.getCode()));
            userRoleDao.saveAll(list);
        }
        entity.setCode(param.getCode());
        entity.setName(param.getName());
        return roleDao.save(entity);
    }


    @Transactional
    @Override
    public RoleEntity del(Long id) throws Exception {
        LocalDateTime now = LocalDateTime.now();
        RoleEntity entity = getById(id);
        List<RoleAuthorityEntity> list = roleAuthorityDao.findAllByGidAndRoleCodeAndDelIsNull(entity.getGid(),entity.getCode());
        list.stream().filter(it -> it.getDel() == null).forEach(item -> item.setDel(now));
        roleAuthorityDao.saveAll(list);
        entity.setDel(now);
        List<UserRoleEntity> list1 = userRoleDao.findAllByGidAndRoleCodeAndDelIsNull(entity.getGid(),entity.getCode());
        list1.forEach(it -> it.setDel(now));
        userRoleDao.saveAll(list1);
        return roleDao.save(entity);
    }


    @BeforeAuthentication
    @Transactional
    @Override
    public void authority(Long gid,String key, List<AuthorityEntity> list) throws Exception {
        LocalDateTime now = LocalDateTime.now();
        RoleEntity entity = roleDao.findByGidAndCode(gid,key);
        if (entity == null) {
            throw new IllegalAccessException("角色不存在");
        }
        List<String> keys = list.stream().map(AuthorityEntity::getCode).collect(Collectors.toList());
        // 检查权限是否存在
        List<AuthorityEntity> list1 = authorityDao.findAllByGidAndCodeIn(gid ,keys);
        if (list1.isEmpty()) {
            throw new IllegalAccessException("权限匹配失败");
        }
        List<RoleAuthorityEntity> oldList = roleAuthorityDao.findAllByGidAndRoleCodeAndDelIsNull(gid,key);
        oldList.forEach( it -> it.setDel(now));

        ArrayList<RoleAuthorityEntity> res = new ArrayList<>();
        for (AuthorityEntity item : list1) {
            Optional<RoleAuthorityEntity> optional = oldList.stream().filter(it -> item.getCode().equals(it.getAuthorityCode())).findAny();
            if (optional.isPresent()) {
                RoleAuthorityEntity roleAuthorityEntity = optional.get();
                roleAuthorityEntity.setDel(null);
                roleAuthorityEntity.setGid(gid);
                res.add(roleAuthorityEntity);
            } else {
                RoleAuthorityEntity build = RoleAuthorityEntity.builder()
                        .authorityCode(item.getCode()).roleCode(key).build();
                build.setGid(gid);
                res.add(build);
            }
        }
        roleAuthorityDao.saveAll(res);
        // 清除已授权中不符合此次授权的权限
        roleAuthorityDao.saveAll(oldList);
    }
}
